// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ParticleFilterCounterManager.cs" company="Microsoft Corporation">
// The MIT License (MIT)
// 
// Copyright (c) 2014, Microsoft Corporation
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace Microsoft.Robotics.PerformanceCounters
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Security;
    using Microsoft.Robotics.Tracing;

    /// <summary>
    /// The counters we support
    /// </summary>
    public enum ParticleFilterCounters
    {
        /// <summary>
        /// The number of particle filter iterations per second
        /// </summary>
        IterationRate,

        /// <summary>
        /// The average weight returned by the observation update across all particles
        /// </summary>
        SingleIterationWeightAverage,

        /// <summary>
        /// The best single-iteration weights
        /// </summary>
        SingleIterationBestWeight,

        /// <summary>
        /// The weight of the most likely particle
        /// </summary>
        BestWeight,

        /// <summary>
        /// The average of all the cumulative weights
        /// </summary>
        WeightAverage,

        /// <summary>
        /// The fast weight average parameter
        /// </summary>
        FastWeightAverage,

        /// <summary>
        /// The slow weight average parameter 
        /// </summary>
        SlowWeightAverage,

        /// <summary>
        /// The number of iterations since the last resampling
        /// </summary>
        PopulationAge,

        /// <summary>
        /// The number of random samples added in the last iteration
        /// </summary>
        RandomSampleCount,

        /// <summary>
        /// The number of particles replaced when resampling.
        /// </summary>
        ReplacedParticleCount,
    }

    /// <summary>
    /// Provides methods for creating and updating the performance counters
    /// </summary>
    public static class ParticleFilterCounterManager
    {
        /// <summary>
        /// The name of the counter group
        /// </summary>
        private static readonly string CategoryName = "Microsoft Robotics Particle Filter";

        /// <summary>
        /// Installs the performance counters
        /// </summary>
        /// <param name="installCounters">If true, the counters are recreated (requires admin permissions)</param>
        public static void Setup(bool installCounters)
        {
            Dictionary<int, CounterCreationData> counterDefinitions = new Dictionary<int, CounterCreationData>();
            counterDefinitions[(int)ParticleFilterCounters.IterationRate] = new CounterCreationData(
                "Iterations / second", 
                "The number of particle filter iterations per second", 
                PerformanceCounterType.RateOfCountsPerSecond32);
            counterDefinitions[(int)ParticleFilterCounters.SingleIterationWeightAverage] = new CounterCreationData(
                "Average observation fitness", 
                "The average weight returned by the observation update across all particles", 
                PerformanceCounterType.NumberOfItems64);
            counterDefinitions[(int)ParticleFilterCounters.SingleIterationBestWeight] = new CounterCreationData(
                "Best observation fitness",
                "The best weight returned by the observation update across all particles",
                PerformanceCounterType.NumberOfItems64);
            counterDefinitions[(int)ParticleFilterCounters.BestWeight] = new CounterCreationData(
                "Best weight",
                "The best cumulative weigth",
                PerformanceCounterType.NumberOfItems64);
            counterDefinitions[(int)ParticleFilterCounters.WeightAverage] = new CounterCreationData(
                "Average weight",
                "The average cumulative weight across all particles",
                PerformanceCounterType.NumberOfItems64);
            counterDefinitions[(int)ParticleFilterCounters.FastWeightAverage] = new CounterCreationData(
                "Fast weight average",
                "The fast weight average parameter",
                PerformanceCounterType.NumberOfItems64);
            counterDefinitions[(int)ParticleFilterCounters.SlowWeightAverage] = new CounterCreationData(
                "Slow weight average",
                "The slow weight average parameter",
                PerformanceCounterType.NumberOfItems64);
            counterDefinitions[(int)ParticleFilterCounters.PopulationAge] = new CounterCreationData(
                "Population age",
                "The number of fitler iterations since the last resamping",
                PerformanceCounterType.NumberOfItems64);
            counterDefinitions[(int)ParticleFilterCounters.RandomSampleCount] = new CounterCreationData(
                "Random samples",
                "The number of random samples added to the population in each iteration",
                PerformanceCounterType.NumberOfItems64);
            counterDefinitions[(int)ParticleFilterCounters.ReplacedParticleCount] = new CounterCreationData(
                "Replaced particles",
                "The number of particles that didn't survive the resampling operation",
                PerformanceCounterType.RateOfCountsPerSecond32);
            
            PerformanceCounterManager.SetupCounters(CategoryName, counterDefinitions, installCounters);
        }

        /// <summary>
        /// Creates all the counters for the specified instance.
        /// </summary>
        /// <param name="instanceName">The name of the instance (agent name + message type)</param>
        /// <returns>The counters for the specified instance</returns>
        public static Dictionary<ParticleFilterCounters, PerformanceCounter> AddInstance(string instanceName)
        {
            return PerformanceCounterManager.AddInstance<ParticleFilterCounters>(CategoryName, instanceName);
        }

        /// <summary>
        /// Retrieves a counter based on instance name and counter name
        /// </summary>
        /// <param name="instanceName">The name of the counter instance</param>
        /// <returns>The counters for the specified instance</returns>
        public static Dictionary<ParticleFilterCounters, PerformanceCounter> GetCounters(string instanceName)
        {
            return PerformanceCounterManager.GetCounters<ParticleFilterCounters>(CategoryName, instanceName);
        }
    }
}
